//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<XFormDialog.h>
///	@path	~/src/editor/wm/
///	@date	2008/10/26
///	@desc	.

#pragma once

#pragma message("Compiling XFormDialog.h ...")

#include "editor/editor.h"

#include "lib/utilities/time.h"

#include "gui/composite/composition.h"
#include "gui/xgui/XForm.h"

#include "editor/xedit/XEditorFrame.h"
#include "editor/wm/DwmComposite.h"

namespace xeres {

	/*! 
		\class	XFormDialog
		\brief
	*/
	class XFormDialog : public CDialogImpl<XFormDialog> , public FrameBase
	{
	public:
		enum { IDD = IDD_DIALOG };

		/// \ctor
		XFormDialog( Ref<IGuiForm> form , const Pair<int>& size , function<void()> tick ) {
			m_tick = tick;
			m_frame = new XEditorFrame( *this );
			if( form.IsValid() )
				m_frame->AddChild( form );
			m_frame->Resize( size.x , size.y );
			m_frame->SetSize( size );
			m_size = size;
		}

		/// \dtor
		~XFormDialog( void ) {
			m_frame->OnClose();
		}

		virtual RefWeak<IGuiForm> GetClientForm( void )
		{
			return m_frame;
		}

		virtual void AcquireUpdate( void )
		{
			Invalidate( FALSE );
		}

		virtual void SetTitle( const wchar_t * title )
		{
			SetWindowText( title );
		}

		virtual HWND GetHwnd( void )
		{
			return m_hWnd;
		}

		BEGIN_MSG_MAP(XFormDialog)
			MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
			MESSAGE_HANDLER(WM_ACTIVATE , OnActivate)
			MESSAGE_HANDLER(WM_PAINT , OnPaint)
			MESSAGE_HANDLER(WM_SIZE , OnSize)
			MESSAGE_HANDLER(WM_ERASEBKGND , OnEraseBkgnd)
			MESSAGE_HANDLER(WM_SETFOCUS , OnSetFocus)
			MESSAGE_HANDLER(WM_KILLFOCUS , OnKillFocus)
			MESSAGE_HANDLER(WM_MOUSELEAVE , OnMouseLeave)
			COMMAND_ID_HANDLER(IDOK, OnCloseCmd)
			COMMAND_ID_HANDLER(IDCANCEL, OnCloseCmd)
		// Dispatch message to XForm.
			if( uMsg == WM_TIMER && wParam == TIMER_TICK ) Tick();
			if( m_frame->DispatchMessages( m_hWnd , uMsg , wParam , lParam ) ) return TRUE; else bHandled = FALSE;
		END_MSG_MAP()

		// Handler prototypes (uncomment arguments if needed):
		//	LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
		//	LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
		//	LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)

		static const int TIME_GAP = static_cast<int>( 1000.f / 30.f );

		LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
		{
			if( m_tick )
			{
				this->SetTimer( TIMER_TICK , TIME_GAP );
				m_last = Counter::Now();
			}

			int border_x = ::GetSystemMetrics( SM_CXSIZEFRAME );
			int border_y = ::GetSystemMetrics( SM_CYSIZEFRAME );
			int caption_y = ::GetSystemMetrics( SM_CYSIZE );
			SetWindowPos( NULL , 0 , 0 , m_size.x + border_x * 2 , m_size.y + border_y * 2 + caption_y , SWP_NOACTIVATE|SWP_NOZORDER );
			CenterWindow( GetParent() );

			__dwm_extend_composition( m_hWnd );
			return TRUE;
		}

		LRESULT OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
		{
			EndDialog(wID);
			return 0;
		}

		LRESULT OnActivate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) {
			// Dummy filter to refresh dispatcher states.
			m_frame->RefreshStates( m_hWnd );
			Invalidate(FALSE);
			bHandled = FALSE;
			return S_OK;
		}
		LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) {
			CPaintDC dc( m_hWnd );

			CRect client;
			this->GetClientRect( &client );

			Layer& layer = m_frame->GetLayer();

			int w = client.Width();
			int h = client.Height();
			dc.StretchDIBits( client.left , client.top , w , h ,
				0 , 0 , layer.GetWidth() , layer.GetHeight() , layer.GetPixel(0,0) , layer.GetBitmapInfo() ,
				DIB_RGB_COLORS , SRCCOPY );

			return S_OK;
		}
		LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/ ) {
// 			CRect client;
// 			this->GetClientRect( &client );
// 			if( client.Width() != m_size.x || client.Height() != m_size.y )
// 			{
// 				CRect win;
// 				GetWindowRect( &win );
// 				int diffx = m_size.x - client.Width();
// 				int diffy = m_size.y - client.Height();
// 				//SetWindowPos( NULL , 0 , 0 , win.Width() + diffx , win.Height() + diffy , SWP_NOACTIVATE|SWP_NOZORDER );
// 			}
			return S_OK;
		}
		LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) {
			return S_OK;
		}
		LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) {
			m_frame->ClearFocus();
			bHandled = TRUE;
			return S_OK;
		}
		LRESULT OnKillFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) {
			m_frame->ClearFocus();
			bHandled = FALSE;
			return S_OK;
		}
		LRESULT OnMouseLeave(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) {
			Updater updater( m_frame );
			m_frame->OnMouseLeave( updater , NULL );
			bHandled = FALSE;
			return S_OK;
		}

		RefWeak<XEditorFrame> GetFrame( void )
		{
			return m_frame;
		}

		void Tick( void )
		{
			Counter current = Counter::Now();
			if( ( current - m_last ).ToMilliSecond() > TIME_GAP && m_tick )
			{
				m_tick();
				m_last = current;
			}
		}

	private:

		//@ data
		Ref<XEditorFrame>	m_frame;
		function<void()>	m_tick;
		Counter				m_last;
		Pair<int>			m_size;
	};
	
} // namespace xeres
